/*
 * Copyright 2022 The Open Islands Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.openislands.oi.worker.manager;

import org.openislands.oi.constant.MessageCodeEnum;
import org.openislands.oi.constant.NodeState;
import org.openislands.oi.dao.entity.NodeDO;
import org.openislands.oi.error.LogicException;
import org.openislands.oi.manager.CommonNodeManager;
import org.openislands.oi.manager.CommonTransactionManager;
import org.openislands.oi.manager.union.UnionPipelineManager;
import org.openislands.oi.pojo.dto.CommonResult;
import org.openislands.oi.pojo.dto.NodeDTO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

@Service
@SuppressWarnings("unused")
public class WorkerNodeManager {
    @Resource
    private CommonNodeManager commonNodeManager;

    @Resource
    private CommonTransactionManager commonTransactionManager;

    @Resource(type = UnionPipelineManager.class)
    private UnionPipelineManager unionPipelineManager;

    public NodeDTO myNodeDTO() {
        return commonNodeManager.myNodeDTO();
    }

    public Boolean myNodeId(String nodeId) {
        return commonNodeManager.myNodeId(nodeId);
    }

    public Boolean verifyNode(NodeDTO nodeDTO) {
        try {
            nodeDTO.setState(NodeState.UNVERIFIED);
            unionPipelineManager.fire(CommonNodeManager.ADD_NODE_AND_ROUTE, nodeDTO);
        } catch (LogicException e) {
            if (e.getResponseMessageCode() != MessageCodeEnum.DUPLICATE_KEY_ERROR) {
                throw e;
            }
            // open transaction to lock the current node record
            commonTransactionManager.newTimeoutTransaction(transactionStatus -> {
                // update node state to unverified
                CommonResult<Object> result = commonNodeManager.updateNodeState(nodeDTO, NodeState.UNVERIFIED);
                if (result.isSuccess()) {
                    // update node and route info
                    nodeDTO.setState(null);
                    unionPipelineManager.fire(CommonNodeManager.UPDATE_NODE_AND_ROUTE, nodeDTO);
                }
            });
        }
        return true;
    }

    public Boolean breakNode(NodeDTO nodeDTO) {
        // update node state to broke
        return commonNodeManager.getNodeManager().update(
                uw -> uw.set(NodeDO::getState, NodeState.BROKE).set(NodeDO::getUpdateTime, new Date())
                        .ne(NodeDO::getState, NodeState.BROKE)
        );
    }
}
